package com.zoe.onelink.core.web.jackson.serializer;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
import com.zoe.onelink.annotation.web.jackson.encryptor.DecryptParam;
import com.zoe.onelink.annotation.data.encryptor.IEncryptor;
import com.zoe.onelink.common.enumeration.ExceptionCodeEnum;
import com.zoe.onelink.common.exception.ApiException;
import com.zoe.onelink.core.property.OnelinkProperties;
import com.zoe.onelink.core.encryptor.EncryptorFactory;
import com.zoe.onelink.core.encryptor.EncryptorManager;
import com.zoe.onelink.util.StrUtil;
import lombok.Setter;

import java.io.IOException;
import java.util.Optional;

/**
 * <p>标题: 解密反序列化器</p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2021</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2021-11-12
 */
@Setter
public class JacksonDecryptSerializer extends JsonDeserializer<String> implements ContextualDeserializer {

    private final OnelinkProperties.Web.Encrypt encryptProp;
    private IEncryptor encryptor;
    private String algorithmName;

    public JacksonDecryptSerializer(OnelinkProperties.Web.Encrypt encryptProp) {
        this.encryptProp = encryptProp;
    }


    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {

        // 如果字段加密未启用,直接返回原参数
        if (!this.encryptProp.isEnabled()) {
            return p.getText();
        }

        // 加密算法实例不存在
        if (this.encryptor == null) {
            throw ApiException.createEx(ExceptionCodeEnum.SERIALIZATION_ENCRYPT_NO_SUCH_ALGORITHM, this.algorithmName);
        }
        try {
            return this.encryptor.decrypt(p.getText());
        } catch (ApiException e) {
            throw e;
        } catch (Exception e) {
            throw ApiException.createEx(ExceptionCodeEnum.DESERIALIZATION_ENCRYPT_VALUE_FAILURE, p.getCurrentName());
        }
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        // 获取字段注解
        DecryptParam decryptParam = Optional.ofNullable(property.getAnnotation(DecryptParam.class))
                .orElse(property.getContextAnnotation(DecryptParam.class));
        if (decryptParam == null) {
            return new StringDeserializer();
        }
        // 算法名称
        String algorithmName = decryptParam.algorithm().name().toUpperCase();
        if (StrUtil.isBlank(algorithmName)) {
            throw ApiException.createEx(ExceptionCodeEnum.SERIALIZATION_ENCRYPT_ALGORITHM_NOT_NULL, property.getName());
        }
        // 根据算法名称创建对应的算法
        IEncryptor encryptor = EncryptorFactory.createEncryptor(decryptParam.algorithm());
        if (encryptor == null) {
            throw ApiException.createEx(ExceptionCodeEnum.SERIALIZATION_ENCRYPT_NO_SUCH_ALGORITHM, algorithmName);
        }
        // 向加密实例管理器注册对应的实例
        EncryptorManager.register(algorithmName, encryptor);
        // 创建加密反序列化器
        JacksonDecryptSerializer jacksonDecryptSerializer = new JacksonDecryptSerializer(this.encryptProp);
        jacksonDecryptSerializer.setAlgorithmName(algorithmName);
        jacksonDecryptSerializer.setEncryptor(encryptor);
        return jacksonDecryptSerializer;
    }
}
